<!DOCTYPE html>
<html>
<head>
<title>抽奖
</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="/choujiang/style.css">
<link rel="stylesheet" href="/choujiang/paperscript.css">
<script src="/choujiang/bootstrap.js"></script>
<script src="/choujiang/paper.js"></script>
</head>
<body class="fullscreen">
    <div id="main">
        <div id="content">

<script type="text/paperscript" canvas="canvas-1">
var data = <%= raw @guest_names_all %>;

/*
 * 0: init; 重置/初始化
 * 1: start; 初始动画阶段
 * 2: active; 出现兑奖区,开始抽奖
 * 3: stop; 暂停
 * 4: win_start; 中奖动画开始
 * 5: win_end; 中奖动画结束
 * 6: scene_end; 场景结束
 * 7: over;
 */
var state = 0,
    helper = {},
    balls = [],
    winner = null,
    group = new Group(),
    targetGroup, 
    spaceText,
    difficultText,
    introBox,
    scenes,
    _pos = view.size;

helper.createText = function(options){
    var text = new PointText(options.x, options.y);
    var style = {};
    if (options.color) {style.fillColor = options.color;}
    if (options.fontSize) {style.fontSize = options.fontSize;}
    text.characterStyle = style;
    if (options.textAlign) {text.paragraphStyle.justification = options.textAlign;}
    text.content = options.content;
    return text;
};

var Ball = Base.extend({
    initialize: function(point, vector, name) {
        if (!vector || vector.isZero()) {
            this.vector = Point.random() * 5;
        } else {
            this.vector = vector * 2;
        }
        this.point = point;
        this.dampen = 0.4;
        // difficult
        this.gravity = 10 - _pos.height / 100 * 1.3;
        this.gravity = this.gravity > 1 ? this.gravity : 1;
        this.bounce = -0.6;
        this.color = new HsbColor(Math.random() * 360, 1, 1);
        this.animate = {
            n: 50,
            preN: Math.abs(Math.random()*50)
        };
        // 大小
        this.radius = 50 * 0.2 + 10;
        this.createPaths();
        this.item.name = name;
        group.addChild(this.item);
    },

    createPaths: function() {
        var overlayPos = this.point + this.radius / 8;
        var compound = new CompoundPath([
            new Path.Circle(this.point, this.radius),
            new Path.Circle(overlayPos, this.radius / 3)
        ]);
        var color = this.color;
        var gradient = new Gradient([color, '#888888'], 'radial');
        compound.children[0].fillColor = new GradientColor(gradient, this.point,
                this.point + this.radius, overlayPos);
        var overlay = new Path.Circle(overlayPos, this.radius / 3);
        var overlayColor = color.clone();
        var fullOverlay = color.clone();
        overlayColor.alpha = 0.3;
        var overlayGradient = new Gradient([new RgbColor(1, 1, 1, 0.5), new RgbColor(1, 1, 1, 1)]);
        overlay.fillColor = new GradientColor(overlayGradient, overlayPos, overlayPos + this.radius / 2);
        this.item = new Group([compound, overlay]);
    },

    iterate: function(i) {
        if (this.item.visible === false) {return false;}
        if (this.animate.preN > 0) {
            this.animate.preN--;
            return false;
        }
        var collisionX = null;
        this.vector.y += this.gravity;
        this.vector.x *= 0.99;
        var pre = this.point + this.vector;
        if (pre.x < this.radius || pre.x > _pos.width - this.radius) {
            this.vector.x *= -this.dampen; 
        }
        if (pre.y < this.radius || pre.y > _pos.height - this.radius) {
            if (Math.abs(this.vector.x) < 3) {
                this.vector = Point.random() * [150, 100] + [-75, 20];
            }
            this.vector.y *= this.bounce;
        }
        if (pre.y < this.radius) {
            collisionX = this.computeCollision(this.point, pre);
        } else {
            collisionX = null;
        }

        var next = this.point + this.vector;
        var max = Point.max(this.radius, next);
        
        if (collisionX && targetGroup && _pos.width/2 -150 <= collisionX && collisionX <= _pos.width/2 + 150) {
            this.item.position = this.point = Point.create(collisionX, this.radius);
            winner = this;
            scenes.fourth();
        } else {
            this.item.position = this.point = Point.min(max, _pos - this.radius);
        }
        this.item.rotate(this.vector.x / 2);
    },

    computeCollision: function(prev, next) {
        var x = Math.abs(prev.y - this.radius) / (Math.abs(next.y - this.radius) + Math.abs(prev.y - this.radius));
        var collisionTarget = prev.x + (next.x - prev.x) * x;
        console.log('碰撞', prev, next, collisionTarget);
        return collisionTarget;
    },

    celebrate: function(){
        if (this.animate.n > 0) {
            var mid = Point.create(_pos.width/2, _pos.height/2);
            if (!this.animate.vector) {
                this.animate.vector = (mid - this.point) / [50, 50];
            }
            this.item.position = this.point = this.point + this.animate.vector;
            this.item.rotate(this.animate.vector.x / 2);
            this.item.scale(1.05);
            this.item.insertAbove(group);
            if (winner.nameText) {winner.nameText.remove();}
            winner.nameText = new PointText(this.item.position - [this.item.name.length*60/2, -20]);
            winner.nameText.content = this.item.name;
            winner.nameText.characterStyle = {
                fontSize: 50-this.animate.n,
                fillColor: 'black'
            };
        }
        this.animate.n = this.animate.n - 1;
        if (this.animate.n === 0) {
            scenes.fifth();
        }
    },

    celebrateEnd: function(){
        for (var i = 0, l = balls.length; i < l; i++) {
            balls[i].animate = {
                n: 50,
                preN: Math.abs(Math.random()*50)
            };
        }
        winner.animate.preN = 0;
    },

    goTrash: function(i){
        if (this.animate.preN > 0) {
            this.animate.preN--;
            return false;
        }
        if (this.animate.n > 0) {
            this.item.rotate(5);
            this.item.scale(1.5);
        }
        this.animate.n = this.animate.n - 1;
        if (this.animate.n === 0) {
            this.item.visible = false;
            balls.splice(i, 1);
        }
    }

});

function sceneInit(){
    for (var i = 0; i < data.length; i++) {
        var position = Point.create(-20, -20);
        var vector = (Point.random() - [0, 0.5]) * [10, 20];
        var ball = new Ball(position, vector, data[i]);
        balls.push(ball);
    }

    spaceText = helper.createText({
        x: 20,
        y: 30,
        color: '#666',
        content: '按空格键暂停'
    });
    spaceText.visible = false;

    difficultText = helper.createText({
        x: 20,
        y: 50,
        color: '#666',
        content: '按a重新开始'
    });
    difficultText.visible = false;
}


function prepareTarget(){
    var textTarget = helper.createText({
        x: _pos.width/2-90,
        y: 40,
        color: 'black',
        content: '撞到天花板中奖',
        fontSize: '20'
    });

    var targetP = new Point(_pos.width/2-150, 0);
    var targetS = new Size(300, 5);
    var targetRect = new Rectangle(targetP, targetS);
    var targetPath = new Path.Rectangle(targetRect);
    targetPath.fillColor = '#D26911';
    targetGroup = new Group([textTarget, targetPath]);
    console.log(targetGroup.position.x, targetGroup.position.x+300);
}

function introFrame(){
    var rect = new Rectangle();
    rect.left = _pos.width/2 - 240;
    rect.right = _pos.width/2 + 240;
    rect.bottom = _pos.height/2 + 30;
    rect.top = _pos.height/2 - 30;
    rect = new Path.RoundRectangle(rect, new Size(15, 15));
    var rectStyle = {
        strokeColor: '#ccc',
        fillColor: 'white',
        strokeWidth: 4
    };
    rect.style = rectStyle;
    var rectText = helper.createText({
        x: _pos.width/2,
        y: _pos.height/2+10,
        color: 'black',
        fontSize: 18,
        textAlign: 'center',
        content: '按回车键开始抽奖'
    });
    introBox = new Group([rect, rectText]);
    introBox.opacity = 0.5;
}

/**
 * Pre-defined animate func. 
 */
function onFrame() {
    var i = 0, l = balls.length;
    if (state == 1 || state == 2){
        for ( ; i < l; i++) {
            balls[i].iterate(i);
        }
    }
    if (state == 4){
        winner.celebrate();
    }
    if (state == 6){
        for ( ; i < l; i++) {
            if (balls[i]){
                balls[i].goTrash(i);
            }
        }
        if (balls.length === 0) {scenes.seventh();}
    }
}

scenes = {
    first: function(){
        introFrame();
        sceneInit();
    },
    second: function(){
        state = 1;
        introBox.visible = false;
        introBox.lastChild.content = '回车键开始抽奖';
        spaceText.visible = true;
        difficultText.visible = true;
        setTimeout(function(){
            introBox.visible = true;
        }, 1000);
    },
    third: function(){
        state = 2;
        prepareTarget();
        introBox.visible = false;
    },
    fourth: function(){
        state = 4;
        spaceText.visible = false;
        difficultText.visible = false;
    },
    fifth: function(){
        winner.celebrateEnd();
        spaceText.content = '按空格宣布中奖名单';
        spaceText.visible = true;
        state = 5;
    },
    sixth: function(){
        state = 6;
    },
    seventh: function(){
        targetGroup.visible = false;
        spaceText.visible = false;
        state = 7;
    }
};

(function(){
    scenes.first();

    /**
     * key operations
     */
    $(document).addEvent('keyup', function(e){

        switch (e.code) {
            case 13:
                if (state === 0) {scenes.second();}
                if (state === 1 && introBox.visible) {scenes.third();}
                break;
            case 32:
                if (state === 2 || state === 3) {
                    state = state === 2 ? 3 : 2;
                }
                if (spaceText.visible === true && state === 5) {scenes.sixth();}
                break;
            /**
             * 调整小球撞上壁的难度
             */
            case 188:
                balls.each(function(item, i){
                    item.gravity = item.gravity - 0.5;
                    item.gravity = item.gravity > 1 ? item.gravity : 1;
                });
                break;
            case 190:
                balls.each(function(item, i){
                    item.gravity = item.gravity + 0.5;
                    item.gravity = item.gravity > 1 ? item.gravity : 1;
                });
                break;
            case 65:
                location.reload();

                break;
            default:
                return false;
        }
    });

    DomEvent.add(window, {
        resize: function(event) {
            balls.each(function(item, i){
                item.gravity = 13 - _pos.height / 100 * 1.3;
                item.gravity = item.gravity > 1 ? item.gravity : 1;
            });
        }
    });
})();

</script>

<div class="canvas">
    <canvas resize="true" id="canvas-1" style="background:#f2f2f2" width="100%"></canvas>
</div>
        </div>
    </div>
</body>
</html>